package cn.iocoder.yudao.module.erp.controller.admin.bom;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.module.erp.controller.admin.bomgroupstandard.vo.BomGroupStandardRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductPlanInfoRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitRespVO;
import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.bomgroupstandard.BomGroupStandardDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO;
import cn.iocoder.yudao.module.erp.enums.DictTypeConstants;
import cn.iocoder.yudao.module.erp.service.bomgroupstandard.BomGroupStandardService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductPlanService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.module.system.service.user.AdminUserServiceImpl;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;

import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;

import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;

import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;

import cn.iocoder.yudao.module.erp.controller.admin.bom.vo.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.bom.ErpBomDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.bom.ErpBomItemsDO;
import cn.iocoder.yudao.module.erp.service.bom.ErpBomService;

@Tag(name = "管理后台 - bom")
@RestController
@RequestMapping("/erp/manufacture/data/bom")
@Validated
public class ErpBomController {

    @Resource
    private ErpBomService bomService;


    @Resource
    private ErpProductService productService;

    @Resource
    private ErpProductUnitService unitService;

    @Resource
    private AdminUserService adminUserService;

    @Resource
    private ErpProductPlanService productPlanService;

    @Resource
    private BomGroupStandardService bomGroupStandardService;

    @Resource
    private DictDataService dictDataService;

    @PostMapping("/create")
    @Operation(summary = "创建bom")
    @PreAuthorize("@ss.hasPermission('erp:bom:create')")
    public CommonResult<String> createBom(@Valid @RequestBody ErpBomSaveReqVO createReqVO) {
        return success(bomService.createBom(createReqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新bom")
    @PreAuthorize("@ss.hasPermission('erp:bom:update')")
    public CommonResult<Boolean> updateBom(@Valid @RequestBody ErpBomSaveReqVO updateReqVO) {
        bomService.updateBom(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除bom")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('erp:bom:delete')")
    public CommonResult<Boolean> deleteBom(@RequestParam("id") Long id) {
        bomService.deleteBom(id);
        // 删除子表
        bomService.deleteBomItemsByBomId(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得bom")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('erp:bom:query')")
    public CommonResult<ErpBomRespVO> getBom(@RequestParam("id") Long id) {
        ErpBomDO bom = bomService.getBom(id);
        return success(BeanUtils.toBean(bom, ErpBomRespVO.class));
    }

    @GetMapping("/page")
    @Operation(summary = "获得bom分页")
    @PreAuthorize("@ss.hasPermission('erp:bom:query')")
    public CommonResult<PageResult<ErpBomRespVO>> getBomPage(@Valid ErpBomPageReqVO pageReqVO) {
        PageResult<ErpBomDO> pageResult = bomService.getBomPage(pageReqVO);
        return success(buildErpBomRespVoPageResult(pageResult));
    }

    private PageResult<ErpBomRespVO> buildErpBomRespVoPageResult(PageResult<ErpBomDO> pageResult) {
        if (CollUtil.isEmpty(pageResult.getList())) {
            return PageResult.empty(pageResult.getTotal());
        }
        // 物料信息
        Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
                convertSet(pageResult.getList(), ErpBomDO::getFmaterialid));
        // BOM组
        List<BomGroupStandardDO> bomGroupList = bomGroupStandardService.getBomGroupStandardListByIds(convertSet(pageResult.getList(), ErpBomDO::getFbomgroupid));
        Map<Long, BomGroupStandardDO> bomGroupStandardDOMap =
                convertMap(bomGroupList, BomGroupStandardDO::getId);
        // BOM类型
        List<DictDataDO> bomTypeList =
                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), DictTypeConstants.ERP_BOM_BOM_TYPE);
        Map<Integer, DictDataDO> bomTypeMap =  convertMap(bomTypeList, DictDataDO::getValueInteger);
        // BOM用途
        List<DictDataDO> bomUseList =
                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), DictTypeConstants.ERP_BOM_BOM_PURPOSE);
        Map<Integer, DictDataDO> bomUseMap =  convertMap(bomUseList, DictDataDO::getValueInteger);

        Map<Long, AdminUserDO> creatorMap =
                adminUserService.getUserMapString(convertSet(pageResult.getList(), ErpBomDO::getCreator));

        Map<Long, AdminUserDO> updaterMap =
                adminUserService.getUserMapString(convertSet(pageResult.getList(), ErpBomDO::getUpdater));

        PageResult<ErpBomRespVO> result =  BeanUtils.toBean(pageResult, ErpBomRespVO.class, erpBomRespVO ->{
            MapUtils.findAndThen(productMap, erpBomRespVO.getFmaterialid(), erpProductRespVO -> erpBomRespVO.setFbarcode(erpProductRespVO.getBarCode()).setFmaterialname(erpProductRespVO.getName()));
            MapUtils.findAndThen(bomGroupStandardDOMap, erpBomRespVO.getFbomgroupid(), bomGroupStandardDO -> erpBomRespVO.setParentidBomGroup(bomGroupStandardDO.getParentid()).setFbomgroupname(bomGroupStandardDO.getName()));
            MapUtils.findAndThen(bomTypeMap, erpBomRespVO.getFbomtype(), dictDataDO -> erpBomRespVO.setFbomtypename(dictDataDO.getLabel()));
            MapUtils.findAndThen(bomUseMap, erpBomRespVO.getFusagetype(), dictDataDO -> erpBomRespVO.setFusagetypename(dictDataDO.getLabel()));
            MapUtils.findAndThen(creatorMap, NumberUtils.parseLong(erpBomRespVO.getCreator()), adminUserDO -> erpBomRespVO.setCreator(adminUserDO.getUsername()));
            MapUtils.findAndThen(updaterMap, Long.parseLong(erpBomRespVO.getUpdater()), adminUserDO -> erpBomRespVO.setUpdater(adminUserDO.getUsername()));
        });
        return result;
    }

    private PageResult<ErpBomItemsRespVO> buildErpBomItemsRespVoPageResult(PageResult<ErpBomItemsDO> pageResult) {
        if (CollUtil.isEmpty(pageResult.getList())) {
            return PageResult.empty(pageResult.getTotal());
        }
        // 物料信息
        Map<Long, ErpProductRespVO> productMap = productService.getProductVOMap(
                convertSet(pageResult.getList(), ErpBomItemsDO::getFmaterialid));
        //单位信息
        Map<Long, ErpProductUnitDO> unitRespVOMap = unitService.getProductUnitMap(
                convertSet(pageResult.getList(),ErpBomItemsDO::getFunitid));
        // 物料属性
        List<DictDataDO> materialAttrList =
                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), DictTypeConstants.ERP_MATERIAL_ATTR);
        Map<Integer, DictDataDO> materialAttrMap =  convertMap(materialAttrList, DictDataDO::getValueInteger);
        // 基本状态
        List<DictDataDO> list =
                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), DictTypeConstants.ERP_BILL_STATUS);
        Map<Integer, DictDataDO> billStatusrMap =  convertMap(list, DictDataDO::getValueInteger);
        // 领送料方式
        List<DictDataDO> materialOutList =
                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), DictTypeConstants.ERP_MATERIAL_OUT);
        Map<Integer, DictDataDO> materialOutMap =  convertMap(materialOutList, DictDataDO::getValueInteger);
        // 消耗类型
        List<DictDataDO> consumeTypeList =
                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), DictTypeConstants.ERP_COST_TYPE);
        Map<Integer, DictDataDO> consumeTypeMap =  convertMap(consumeTypeList, DictDataDO::getValueInteger);
        // 工序
        List<DictDataDO> processList =
                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), DictTypeConstants.ERP_BOM_PROCESS);
        Map<Integer, DictDataDO> processMap =  convertMap(processList, DictDataDO::getValueInteger);

        PageResult<ErpBomItemsRespVO> result =  BeanUtils.toBean(pageResult, ErpBomItemsRespVO.class, erpBomItemsRespVO ->{
            MapUtils.findAndThen(unitRespVOMap, erpBomItemsRespVO.getFunitid(), erpProductUnitDO -> erpBomItemsRespVO.setFunitname(erpProductUnitDO.getName()));
            MapUtils.findAndThen(productMap, erpBomItemsRespVO.getFmaterialid(), product -> erpBomItemsRespVO.setFbarcode(product.getBarCode()).setFmaterialname(product.getName())
                    .setFmodel(product.getStandard()));
            MapUtils.findAndThen(materialAttrMap, erpBomItemsRespVO.getFmaterialprop(), materialAttr -> erpBomItemsRespVO.setFmaterialpropname(materialAttr.getLabel()));
            MapUtils.findAndThen(billStatusrMap, erpBomItemsRespVO.getFbasestatus(), billStatus -> erpBomItemsRespVO.setFbasestatusname(billStatus.getLabel()));
            MapUtils.findAndThen(materialOutMap, erpBomItemsRespVO.getFissmode(), materialOut -> erpBomItemsRespVO.setFissmodename(materialOut.getLabel()));
            MapUtils.findAndThen(consumeTypeMap, erpBomItemsRespVO.getFconsumetype(), consumeType -> erpBomItemsRespVO.setFconsumetypename(consumeType.getLabel()));
            MapUtils.findAndThen(processMap, erpBomItemsRespVO.getFprocess(), process -> erpBomItemsRespVO.setFprocessname(process.getLabel()));
        });
        return result;
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出bom Excel")
    @PreAuthorize("@ss.hasPermission('erp:bom:export')")
    @ApiAccessLog(operateType = EXPORT)
    public void exportBomExcel(@Valid ErpBomPageReqVO pageReqVO,
              HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<ErpBomDO> list = bomService.getBomPage(pageReqVO).getList();
        // 导出 Excel
        ExcelUtils.write(response, "bom.xls", "数据", ErpBomRespVO.class,
                        BeanUtils.toBean(list, ErpBomRespVO.class));
    }

    // ==================== 子表（bom分录） ====================

    @GetMapping("/bom-items/page")
    @Operation(summary = "获得bom分录分页")
    @Parameter(name = "fparentid", description = "单据头")
    @PreAuthorize("@ss.hasPermission('erp:bom:query')")
    public CommonResult<PageResult<ErpBomItemsRespVO>> getBomItemsPage(PageParam pageReqVO,
       @RequestParam("fparentid") Long fparentid) {
        PageResult<ErpBomItemsDO> pageResult = bomService.getBomItemsPage(pageReqVO, fparentid);
        return success(buildErpBomItemsRespVoPageResult(pageResult));
    }

    @PostMapping("/bom-items/create")
    @Operation(summary = "创建bom分录")
    @PreAuthorize("@ss.hasPermission('erp:bom:create')")
    public CommonResult<String> createBomItems(@Valid @RequestBody ErpBomItemsDO bomItems) {
        return success(bomService.createBomItems(bomItems));
    }

    @PutMapping("/bom-items/update")
    @Operation(summary = "更新bom分录")
    @PreAuthorize("@ss.hasPermission('erp:bom:update')")
    public CommonResult<Boolean> updateBomItems(@Valid @RequestBody ErpBomItemsDO bomItems) {
        bomService.updateBomItems(bomItems);
        return success(true);
    }

    @DeleteMapping("/bom-items/delete")
    @Parameter(name = "id", description = "编号", required = true)
    @Operation(summary = "删除bom分录")
    @PreAuthorize("@ss.hasPermission('erp:bom:delete')")
    public CommonResult<Boolean> deleteBomItems(@RequestParam("id") String id) {
        bomService.deleteBomItems(id);
        return success(true);
    }

	@GetMapping("/bom-items/get")
	@Operation(summary = "获得bom分录")
	@Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('erp:bom:query')")
	public CommonResult<ErpBomItemsDO> getBomItems(@RequestParam("id") String id) {
	    return success(bomService.getBomItems(id));
	}

}